package com.yvon.maple.service.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.yvon.boot.mybatis.BaseServiceImpl;
import com.yvon.maple.cloud.api.base.feign.FileFeignClient;
import com.yvon.maple.cloud.api.system.dto.SecurityUserDTO;
import com.yvon.maple.constants.FileKey;
import com.yvon.maple.enums.UserTypeEnum;
import com.yvon.maple.service.system.mapper.UserMapper;
import com.yvon.maple.service.system.dto.UserRoleDTO;
import com.yvon.maple.service.system.entity.User;
import com.yvon.maple.service.system.vo.ResetPasswordVO;
import com.yvon.maple.service.system.vo.UpdatePasswordVO;
import com.yvon.maple.service.system.service.UserRoleService;
import com.yvon.maple.service.system.service.UserService;
import com.yvon.maple.utils.DataConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.yvon.maple.constants.SystemConstant.Common.LIMIT_ONE;

/**
 * @author : Yvon
 * @version : 1.0
 * @since : 2021/3/15
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User, UserMapper> implements UserService {

    private static final String COLUMN_USERNAME = "username";

    private static final String COLUMN_PHONE = "phone";

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private FileFeignClient fileFeignClient;

    @Override
    public boolean save(User entity, List<Long> roleIds) {
        entity.setId(IdWorker.getId());
        checkUniqueness(COLUMN_USERNAME, entity.getUsername(), null, "账号已存在");
        checkUniqueness(COLUMN_PHONE, entity.getPhone(), null, "手机号码已存在");
        entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        updateAvatar(entity.getAvatar(), entity.getId());
        updatePhoto(entity.getPhoto(), entity.getId());
        return save(entity) && userRoleService.save(entity.getId(), roleIds);
    }



    @Override
    public boolean update(User entity, List<Long> roleIds) {
        checkUniqueness(COLUMN_PHONE, entity.getPhone(), entity.getId(), "手机号码已存在");
        entity.setUsername(null);
        entity.setPassword(null);
        updateAvatar(entity.getAvatar(), entity.getId());
        updatePhoto(entity.getPhoto(), entity.getId());
        return updateById(entity) && userRoleService.save(entity.getId(), roleIds);
    }

    @Override
    public User getByUsername(String username) {
        return lambdaQuery()
                .eq(User::getUsername, username)
                .last(LIMIT_ONE)
                .one();
    }

    @Override
    public User getLdapByUsername(String username) {
        return lambdaQuery()
                .eq(User::getUsername, username)
                .eq(User::getUserType, UserTypeEnum.LDAP)
                .last(LIMIT_ONE)
                .one();
    }

    @Override
    public SecurityUserDTO loadByUsername(String username) {
        SecurityUserDTO securityUserDTO = null;
        User user = lambdaQuery()
                .eq(User::getUsername, username)
                .last(LIMIT_ONE)
                .one();
        if (Objects.nonNull(user)) {
            securityUserDTO = DataConverter.convert(user, SecurityUserDTO.class);
            List<UserRoleDTO> roles = userRoleService.getByUserId(user.getId());
            if (CollUtil.isNotEmpty(roles)) {
                securityUserDTO.setRoleCodes(roles.stream().map(UserRoleDTO::getCode).collect(Collectors.toList()));
            }
        }
        return securityUserDTO;
    }

    @Override
    public User getByMobile(String mobile) {
        return lambdaQuery()
                .eq(User::getPhone, mobile)
                .last(LIMIT_ONE)
                .one();
    }

    @Override
    public User getByEmail(String email) {
        return lambdaQuery()
                .eq(User::getEmail, email)
                .last(LIMIT_ONE)
                .one();
    }

    @Override
    public Set<String> getEmailByUserIds(Set<Long> userIds) {
        List<User> userList = lambdaQuery()
                .in(User::getId, userIds)
                .select(User::getEmail)
                .list();
        return CollUtil.isNotEmpty(userList)? userList.stream().map(User::getEmail).collect(Collectors.toSet()) : null;
    }



    @Override
    public Set<String> getMobileByUserIds(Set<Long> userIds) {
        List<User> userList = lambdaQuery()
                .in(User::getId, userIds)
                .select(User::getPhone)
                .list();
        return CollUtil.isNotEmpty(userList)? userList.stream().map(User::getPhone).collect(Collectors.toSet()) : null;
    }

    @Override
    public Set<Long> getUserIdsByRoleIds(Set<Long> roleIds) {
        return Sets.newHashSet(userRoleService.getUserIdsByRoleIds(Lists.newArrayList(roleIds)));
    }

    @Override
    public Set<String> getEmailByRoleIds(Set<Long> roleIds) {
        Set<Long> userId = getUserIdsByRoleIds(roleIds);
        return getEmailByUserIds(userId);
    }

    @Override
    public Set<String> getMobileByRoleIds(Set<Long> roleIds) {
        Set<Long> userId = getUserIdsByRoleIds(roleIds);
        return getMobileByUserIds(userId);
    }


    @Override
    public boolean updatePassword(UpdatePasswordVO vo) {
        User user = getById(vo.getId());
        Assert.notNull(user, "账号不存在");
        Assert.isTrue(passwordEncoder.matches(vo.getOldPassword(), user.getPassword()), "旧密码错误");
        Assert.isFalse(passwordEncoder.matches(vo.getPassword(), user.getPassword()), "新旧密码不能一样");
        user.setPassword(passwordEncoder.encode(vo.getPassword()));
        return updateById(user);
    }

    @Override
    public boolean resetPassword(ResetPasswordVO vo) {
        User user = getById(vo.getId());
        Assert.notNull(user, "账号不存在");
        user.setPassword(passwordEncoder.encode(vo.getPassword()));
        return updateById(user);
    }

    private void updateAvatar(Long avatar, Long id) {
        if (Objects.nonNull(avatar)) {
            fileFeignClient.coverSave(id, FileKey.AVATAR, avatar);
        }
    }

    private void updatePhoto(Set<Long> photo, Long id) {
        if (CollUtil.isNotEmpty(photo)) {
            fileFeignClient.coverSave(id, FileKey.PHOTO, photo);
        }
    }

}
